今天,我們來看 Rust 的生命週期(Lifetime)概念。生命週期是 Rust 借用檢查器用來確保所有借用都是有效的機制,它與所有權系統密切相關。
生命週期是 Rust 編譯器用來確保所有的引用在被使用時都是有效的。它告訴編譯器不同引用的有效範圍,以防止懸垂指針的產生。
生命週期參數的名稱以撇號(')開頭,通常使用小寫字母,如 'a:
&i32 // 一個引用
&'a i32 // 具有顯式生命週期的引用
&'a mut i32 // 具有顯式生命週期的可變引用
當函數返回一個引用時,其生命週期必須與某個輸入參數的生命週期相關:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
這個函數聲明了一個泛型生命週期 'a,並用它標註了兩個參數和返回值。
當結構體包含引用時,我們需要為每個引用標註生命週期:
struct Excerpt<'a> {
part: &'a str,
}
這表示 Excerpt 實例的生命週期不能超過 part 字段引用的字串切片。
Rust 有一些生命週期省略規則,在某些常見模式下允許我們省略顯式的生命週期標註:
'static 是一個特殊的生命週期,它存活於整個程序運行期間:
let s: &'static str = "I have a static lifetime.";
我們可以使用生命週期參數來限制泛型類型:
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: Display,
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
讓我們看一個更複雜的範例,展示生命週期在實際程式中的應用:
struct Config<'a> {
host: &'a str,
port: u16,
}
struct Client<'a> {
config: &'a Config<'a>,
}
impl<'a> Client<'a> {
fn new(config: &'a Config) -> Client<'a> {
Client { config }
}
fn get_host(&self) -> &'a str {
self.config.host
}
}
fn main() {
let config = Config {
host: "localhost",
port: 8080,
};
let client = Client::new(&config);
println!("Connected to: {}", client.get_host());
}